package
{
	import com.greensock.TweenLite;
	import com.greensock.easing.Bounce;
	import com.greensock.easing.Cubic;
	
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public class BJClone extends Sprite implements ITileGame
	{
		public static const TILE_SIZE:Number = 30;
		public static const WIDTH:int = 8;
		public static const HEIGHT:int = 12;
		
		public static const COLORS:Array = [0xff0000,0x00ff00,0x0000ff,0xffff00,0xff00ff];
		private var m_stage:Stage;
		private var m_allTiles:Vector.<Tile>;
		private var m_helper:TileGameHelper;
		public function BJClone(stage:Stage)
		{
			super();
			m_helper = new TileGameHelper(this);
			m_stage = stage;
			m_allTiles = new Vector.<Tile>;
			// support autoOrients
			stage.frameRate = 60;
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			
			initializeInputHandling();
						
			addEventListener(Event.ADDED_TO_STAGE, function(e:Event):void{
				start();
			});
		}
		
		
		public function addTile(tile:Tile):void
		{
			m_allTiles.push(tile);
			addChild(tile.display);			
		}
				
		private function initializeInputHandling():void
		{
			var mouseDownLoc:Point = new Point();
			var isDown:Boolean = false;
			var tile:Tile;
			var curPos:Point = new Point();
			var adjTiles:Vector.<Tile>;
			var adjTile:Tile;
			m_stage.addEventListener(MouseEvent.MOUSE_DOWN, function(me:MouseEvent):void{
				isDown = true;
				mouseDownLoc.setTo(me.stageX, me.stageY);
				tile = m_helper.tileHitTest(me.stageX, me.stageY, stage);
				if(tile && tile.interactable)
				{
					adjTiles = m_helper.getAdjacentTiles(tile);	
				}
				
			});
			m_stage.addEventListener(MouseEvent.MOUSE_MOVE, function(me:MouseEvent):void{
				curPos.setTo(me.stageX, me.stageY);
				if(isDown)
				{
					if(tile && tile.interactable)
					{
						for each(adjTile in adjTiles)
						{
							if(adjTile.display.getBounds(m_stage).containsPoint(curPos))
							{
								attemptSwap(tile, adjTile);	
							}
						}
					}
				}
			});
			m_stage.addEventListener(MouseEvent.MOUSE_UP, function(me:MouseEvent):void{
				isDown = false;
			});
			
		}
		
		private function attemptSwap(tile1:Tile, tile2:Tile):void
		{
			var validSwap:Boolean = false;
			tile1.interactable = false;
			tile2.interactable = false;
		
			var _loc1:Point = new Point(tile1.x, tile1.y);
			var _loc2:Point = new Point(tile2.x, tile2.y);
			
			tile1.x = _loc2.x;
			tile1.y = _loc2.y;
			
			tile2.x = _loc1.x;
			tile2.y = _loc1.y;
			
			var connected1:Vector.<Tile> = m_helper.getConnectedMatch3Tiles(tile1, new Vector.<Tile>);
			var connected2:Vector.<Tile> = m_helper.getConnectedMatch3Tiles(tile2, new Vector.<Tile>);
			if(connected1.length >= 3 || connected2.length >= 3)
			{
				validSwap = true;
			}
			
			if(connected1.length >= 3)
			{
				m_helper.disableTiles(connected1);
			}
			
			if(connected2.length >= 3)
			{
				m_helper.disableTiles(connected2);
			}			
			
			TweenLite.to(tile1.display, .5, {x: tile1.x*tile1.tileSize, y:tile1.y*tile1.tileSize, onComplete: function():void{
				if(validSwap)
				{
					if(connected1.length >= 3)
					{
						scoreTiles(connected1);	
					}
					else
					{
						tile1.interactable = true;
						m_helper.enableTiles(connected1);
					}
				}
				else
				{
					tile1.x = _loc1.x;
					tile1.y = _loc1.y;
					TweenLite.to(tile1.display, .5, {x: tile1.x*tile1.tileSize, y:tile1.y*tile1.tileSize, onComplete: function():void{
						tile1.interactable = true;
					}});					
				}
			}});
			
			TweenLite.to(tile2.display, .5, {x: tile2.x*tile2.tileSize, y:tile2.y*tile2.tileSize, onComplete: function():void{
				
				if(validSwap)
				{
					
					if(connected2.length >= 3)
					{
						scoreTiles(connected2);	
					}
					else
					{
						tile2.interactable = true;
						m_helper.enableTiles(connected2);
					}
				}
				else
				{
					tile2.x = _loc2.x;
					tile2.y = _loc2.y;
					
					TweenLite.to(tile2.display, .5, {x: tile2.x*tile2.tileSize, y:tile2.y*tile2.tileSize, onComplete:function():void{
						tile2.interactable = true;
					}});					
				}
			}});
		}
		
		public function getBoardWidth():int
		{
			return WIDTH;
		}
		
		public function getBoardHeight():int
		{
			return HEIGHT;
		}		
		
		
		private function evaluateTile(tile:Tile):void
		{
			var connectedTiles:Vector.<Tile> = m_helper.getConnectedMatch3Tiles(tile, new Vector.<Tile>);
			if(connectedTiles.length >= 3)
			{
				scoreTiles(connectedTiles);
			}
		}

		public function createNewTile(x:int,y:int):Tile
		{
			return Tile.createNewTile(x, y, TILE_SIZE, COLORS);
		}
		
		private function dropNewTiles():void
		{
			m_helper.dropNewTiles();
		}
		
		public function getTileAt(x:int, y:int):Tile
		{
			return m_helper.getTileAt(x, y);
		}
		
		private function start():void
		{
			
			initialTileDrop(function():void{
				stage.addEventListener(Event.ENTER_FRAME, onFrame);
			});
		}
		
		private function initialTileDrop(onComplete:Function):void
		{
			var tiles:Vector.<Tile> = new Vector.<Tile>;
			for(var i:int = 0, il:int = WIDTH; i < il; i++)
			{
				for(var j:int = 0, jl:int = HEIGHT; j < jl; j++)
				{
					var tile:Tile = createNewTile(i,j);
					tiles.push(tile);
					m_allTiles.push(tile);
					addChild(tile.display);
				}
			}
			
			var tdg:TileDropGroup = new TileDropGroup(tiles);
			tdg.dropStyle = TileDropGroup.DROP_STYLE_BULK_NEW;
			tdg.go(onComplete());
		}
		
		public function getAllTiles():Vector.<Tile>
		{
			return m_allTiles;
		}
		
		private function scoreTiles(tiles:Vector.<Tile>):void
		{
			m_helper.destroyTiles(tiles);
		}		
		
		
		public static function getRandomElementFromArray(array:Array):*
		{
			var idx:int = Math.floor(Math.random()*array.length);
			return array[idx];
		}
		
		private function onFrame(e:Event):void
		{
			for each(var tile:Tile in m_allTiles)
			{
				if(tile.interactable)
				{
					var connected:Vector.<Tile> = m_helper.getConnectedMatch3Tiles(tile, new Vector.<Tile>);
					if(connected.length > 0)
					{
						scoreTiles(connected);
					}
				}
			}

			m_helper.onFrame();
		}
	}
}